/*
 * libiio - AD9361 IIO streaming example
 *
 * Copyright (C) 2014 IABG mbH
 * Author: Michael Feilen <feilen_at_iabg.de>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 **/

#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <iio.h>
#include <stdlib.h>

//-------------TCP ------------------
#include "stdio.h"
#include "string.h"
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<netdb.h>
#include<arpa/inet.h>

#include <time.h> 
#include <unistd.h>  
#include <fcntl.h>             

#include <dirent.h>             
#include <sys/stat.h>        
#include <sys/types.h>        
#include <stdlib.h>

#include <assert.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

#include<arpa/inet.h> //inet_addr
#include<pthread.h> //for threading , link with lpthread

static volatile int do_exit = 0;

#define MAX_COLUMN_LEN    32
#define MAX_LISTEN 1024
#define MAX_LINE 1024

#define MAX_PACK 4096
#define MAX_PACK 4096

int Socket(int domain, int type, int protocol)
{
	int sockfd = socket(domain, type, protocol);
	if (sockfd < 0)
	{
		perror("init socket:  ");
		exit(0);
	}
	return sockfd;
}

void Bind(int sockfd, struct sockaddr *myaddr, int addrlen)
{
	if (bind(sockfd, myaddr, addrlen) < 0)
	{
		perror("bind");
		exit(0);
	}
}

void Listen(int sockfd, int backlog)
{
	if (listen(sockfd, backlog) < 0)
	{
		perror("listen");
		exit(0);
	}
}

int Accept(int listenfd, struct sockaddr *addr, int *addrlen)
{
	int clientfd = accept(listenfd, addr, addrlen);
	if (clientfd < 0)
	{
		perror("accept");
		exit(0);
	}
	return clientfd;
}

void Close(int clientfd)
{
	if (close(clientfd) < 0)
	{
		perror("close");
		exit(0);
	}
}
struct hostent* Gethostbyaddr(const char *addr, int len, int domain)
{
	struct hostent* host = gethostbyaddr(addr, len, domain);
	if (NULL == host)
	{
		perror("host_by_addr");
		exit(0);
	}
	return host;
}

ssize_t Read(int fd, void* buf, size_t n)
{
	ssize_t num = recv(fd, buf, n, 0);
	return num;
}

ssize_t SentMydata(int listenfd, const char *buffer, size_t size)
{
	ssize_t n = 0;

	n = write(listenfd, (char *) buffer, size);

	return n;
}

//--------------------------------

/* helper macros */
#define MHZ(x) ((long long)(x*1000000.0 + .5))
#define GHZ(x) ((long long)(x*1000000000.0 + .5))

#define IIO_ENSURE(expr) { \
	if (!(expr)) { \
		(void) fprintf(stderr, "assertion failed (%s:%d)\n", __FILE__, __LINE__); \
		(void) abort(); \
	} \
}

/* RX is input, TX is output */
enum iodev
{
	RX, TX
};

/* common RX and TX streaming params */
struct stream_cfg
{
	long long bw_hz; // Analog banwidth in Hz
	long long fs_hz; // Baseband sample rate in Hz
	long long lo_hz; // Local oscillator frequency in Hz
	int mgc_value; //
	const char* rfport; // Port name
	const char* gian_control_mode; //

};

/* static scratch mem for strings */
static char tmpstr[64];

/* IIO structs required for streaming */
static struct iio_context *ctx = NULL;
static struct iio_channel *rx0_i = NULL;
static struct iio_channel *rx0_q = NULL;
static struct iio_channel *tx0_i = NULL;
static struct iio_channel *tx0_q = NULL;
static struct iio_buffer *rxbuf = NULL;
static struct iio_buffer *txbuf = NULL;

struct iio_device *tx;
struct iio_device *rx;

static bool stop;

/* cleanup and exit */
static void shutdown1()
{
	printf("* Destroying buffers\n");
	if (rxbuf)
	{
		iio_buffer_destroy(rxbuf);
	}
	if (txbuf)
	{
		iio_buffer_destroy(txbuf);
	}

	printf("* Disabling streaming channels\n");
	if (rx0_i)
	{
		iio_channel_disable(rx0_i);
	}
	if (rx0_q)
	{
		iio_channel_disable(rx0_q);
	}
	if (tx0_i)
	{
		iio_channel_disable(tx0_i);
	}
	if (tx0_q)
	{
		iio_channel_disable(tx0_q);
	}

	printf("* Destroying context\n");
	if (ctx)
	{
		iio_context_destroy(ctx);
	}
	exit(0);
}

static void handle_sig(int sig)
{
	printf("Waiting for process to finish... Got signal %d\n", sig);
	stop = true;
}

/* check return value of attr_write function */
static void errchk(int v, const char* what)
{
	if (v < 0)
	{
		fprintf(stderr, "Error %d writing to channel \"%s\"\nvalue may not be supported.\n", v, what);
		shutdown1();
	}
}

/* write attribute: long long int */
static void wr_ch_lli(struct iio_channel *chn, const char* what, long long val)
{
	errchk(iio_channel_attr_write_longlong(chn, what, val), what);
}

/* write attribute: string */
static void wr_ch_str(struct iio_channel *chn, const char* what, const char* str)
{
	errchk(iio_channel_attr_write(chn, what, str), what);
}

/* helper function generating channel names */
static char* get_ch_name(const char* type, int id)
{
	snprintf(tmpstr, sizeof(tmpstr), "%s%d", type, id);
	return tmpstr;
}

/* returns ad9361 phy device */
static struct iio_device* get_ad9361_phy(struct iio_context *ctx)
{
	struct iio_device *dev = iio_context_find_device(ctx, "ad9361-phy");
	IIO_ENSURE(dev && "No ad9361-phy found");
	return dev;
}

/* finds AD9361 streaming IIO devices */
static bool get_ad9361_stream_dev(struct iio_context *ctx, enum iodev d, struct iio_device **dev)
{
	switch (d)
	{
	case TX:
		*dev = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc");
		return *dev != NULL;
	case RX:
		*dev = iio_context_find_device(ctx, "cf-ad9361-lpc");
		return *dev != NULL;
	default:
		IIO_ENSURE(0)
		;
		return false;
	}
}

/* finds AD9361 streaming IIO channels */
static bool get_ad9361_stream_ch(__notused struct iio_context *ctx, enum iodev d, struct iio_device *dev, int chid, struct iio_channel **chn)
{
	*chn = iio_device_find_channel(dev, get_ch_name("voltage", chid), d == TX);
	if (!*chn)
	*chn = iio_device_find_channel(dev, get_ch_name("altvoltage", chid), d == TX);
	return *chn != NULL;
}

/* finds AD9361 phy IIO configuration channel with id chid */
static bool get_phy_chan(struct iio_context *ctx, enum iodev d, int chid, struct iio_channel **chn)
{
	switch (d)
	{
	case RX:
		*chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("voltage", chid), false);
		return *chn != NULL;
	case TX:
		*chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("voltage", chid), true);
		return *chn != NULL;
	default:
		IIO_ENSURE(0)
		;
		return false;
	}
}

/* finds AD9361 local oscillator IIO configuration channels */
static bool get_lo_chan(struct iio_context *ctx, enum iodev d, struct iio_channel **chn)
{
	switch (d)
	{
	// LO chan is always output, i.e. true
	case RX:
		*chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("altvoltage", 0), true);
		return *chn != NULL;
	case TX:
		*chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("altvoltage", 1), true);
		return *chn != NULL;
	default:
		IIO_ENSURE(0)
		;
		return false;
	}
}

/* applies streaming configuration through IIO */
bool cfg_ad9361_streaming_ch(struct iio_context *ctx, struct stream_cfg *cfg, enum iodev type, int chid)
{
	struct iio_channel *chn = NULL;

	// Configure phy and lo channels
	printf("* Acquiring AD9361 phy channel %d\n", chid);
	if (!get_phy_chan(ctx, type, chid, &chn))
	{
		return false;
	}
	wr_ch_str(chn, "rf_port_select", cfg->rfport);
	wr_ch_str(chn, "gain_control_mode", cfg->gian_control_mode);
	if (strstr(cfg->gian_control_mode, "manual") && type == RX)
	{
		wr_ch_lli(chn, "hardwaregain", cfg->mgc_value);
	}
	wr_ch_lli(chn, "rf_bandwidth", cfg->bw_hz);
	wr_ch_lli(chn, "sampling_frequency", cfg->fs_hz);

	// Configure LO channel
	printf("* Acquiring AD9361 %s lo channel\n", type == TX ? "TX" : "RX");
	if (!get_lo_chan(ctx, type, &chn))
	{
		return false;
	}
	wr_ch_lli(chn, "frequency", cfg->lo_hz);
	return true;
}

bool cfg_ad9361_streaming_ch_LO(struct iio_context *ctx, struct stream_cfg *cfg, enum iodev type, int chid)
{
	struct iio_channel *chn = NULL;

	if (!get_lo_chan(ctx, type, &chn))
	{
		return false;
	}
	wr_ch_lli(chn, "frequency", cfg->lo_hz);
	return true;
}

bool cfg_ad9361_streaming_ch_mgc(struct iio_context *ctx, struct stream_cfg *cfg, enum iodev type, int chid)
{
	struct iio_channel *chn = NULL;
	//printf("* Acquiring AD9361 phy channel %d\n", chid);
	if (!get_phy_chan(ctx, type, chid, &chn))
	{
		return false;
	}

	if (strstr(cfg->gian_control_mode, "manual") && type == RX)
	{
		wr_ch_lli(chn, "hardwaregain", cfg->mgc_value);
	}

	return true;
}

bool SetRxL0(struct iio_context *ctx, long long val)
{
	struct iio_channel *chn = NULL;
	if (!get_lo_chan(ctx, RX, &chn))
	{
		return false;
	}
	wr_ch_lli(chn, "frequency", val);
	return true;
}

unsigned char CMD_SET_FREQ = 0x1;
unsigned char CMD_SET_SAMPLE_RATE = 0x2;
unsigned char CMD_SET_TUNER_GAIN_MODE = 0x3;
unsigned char CMD_SET_GAIN = 0x4;
unsigned char CMD_SET_FREQ_COR = 0x5;
unsigned char CMD_SET_AGC_MODE = 0x8;
unsigned char CMD_SET_TUNER_GAIN_INDEX = 0xd;

int ClientNo = -1;
int start = 0;
int reconlict = 0;

unsigned int freq = 91400000;
unsigned int fs = 3200000;

struct stream_cfg rxcfg;
int update_cmd = 0;
int update_mgc = 0;
int update_lo = 0;

void echo(int listenfd)
{
}

/* simple configuration and streaming */
/* usage: 
 * Default context, assuming local IIO devices, i.e., this script is run on ADALM-Pluto for example
 $./a.out
 * URI context, find out the uri by typing `iio_info -s` at the command line of the host PC
 $./a.out usb:x.x.x 
 */
#define closesocket close
#define SOCKADDR struct sockaddr
#define SOCKET int
#define SOCKET_ERROR -1

static SOCKET s;

static pthread_t tcp_worker_thread;
static pthread_t command_thread;
static pthread_cond_t exit_cond;
static pthread_mutex_t exit_cond_lock;

static pthread_mutex_t ll_mutex;
static pthread_cond_t cond;

static struct llist *ll_buffers = 0;

typedef struct
{ /* structure size must be multiple of 2 bytes */
	uint8_t tuner_type;
	uint8_t tuner_gain_count;
    char magic[20];
} dongle_info_t;

static pthread_t tcp_worker_thread;
static pthread_t command_thread;

static void sighandler(int signum)
{
	fprintf(stderr, "Signal caught, exiting!\n");
	//rtlsdr_cancel_async(dev);
	do_exit = 1;
}

static void *tcp_worker(void *arg)
{
	struct llist *curelem, *prev;
	int bytesleft, bytessent, index;
	struct timeval tv =
	{ 1, 0 };
	struct timespec ts;
	struct timeval tp;
	fd_set writefds;
	int r = 0;

	rxcfg.bw_hz = MHZ(20);   // 2 MHz rf bandwidth
	//rxcfg.fs_hz = MHZ(3.2);   // 2.5 MS/s rx sample rate
	//rxcfg.lo_hz = MHZ(91.4); // 2.5 GHz rf frequency
	rxcfg.rfport = "A_BALANCED"; // port A (select for rf freq.)

	//SetRxL0(ctx,rxcfg.lo_hz);

//	iio_channel_disable(rx0_i);
//	iio_channel_disable(rx0_q);
//	IIO_ENSURE(cfg_ad9361_streaming_ch(ctx, &rxcfg, RX, 0) && "RX port 0 not found");
//
//	IIO_ENSURE(get_ad9361_stream_ch(ctx, RX, rx, 0, &rx0_i) && "RX chan i not found");
//	IIO_ENSURE(get_ad9361_stream_ch(ctx, RX, rx, 1, &rx0_q) && "RX chan q not found");
//	iio_channel_enable(rx0_i);
//	iio_channel_enable(rx0_q);

	printf("Zo=%lld,fs=%lld bw =%lld %s\r\n", (rxcfg.lo_hz), (rxcfg.fs_hz), (rxcfg.bw_hz), rxcfg.rfport);

	while (1)
	{
		if (do_exit)
		{
			printf("sent poll exite !!!\n");
			pthread_exit(0);
			return;
		}

		ssize_t nbytes_rx, nbytes_tx;
		char *p_dat, *p_end;
		ptrdiff_t p_inc;

		// Refill RX buffer
		nbytes_rx = iio_buffer_refill(rxbuf);
		if (nbytes_rx < 0)
		{
			printf("Error refilling buf %d\n", (int) nbytes_rx);
			shutdown1();
		}

		// READ: Get pointers to RX buf and read IQ from RX buf port 0
		p_inc = iio_buffer_step(rxbuf);
		p_end = iio_buffer_end(rxbuf);

		p_dat = (char *) iio_buffer_first(rxbuf, rx0_i);
		bytessent = send(s, (char *) p_dat, (int) (p_end - p_dat), 0);
		//printf( "sent = %d \r\n",bytessent);

		if (update_cmd)
		{
			update_cmd = 0;
			//SetRxL0(ctx,rxcfg.lo_hz);
			//printf("lo=%d,fs=%d\r\n",ntohl(rxcfg.lo_hz),ntohl(rxcfg.fs_hz));
			printf("Lo=%lld,fs=%lld bw =%lld %s\r\n", (rxcfg.lo_hz), (rxcfg.fs_hz), (rxcfg.bw_hz), rxcfg.rfport);
			IIO_ENSURE(cfg_ad9361_streaming_ch(ctx, &rxcfg, RX, 0) && "RX port 0 not found");
		}

		if (update_mgc)
		{
			update_mgc = 0;
			printf("set gain=%d \r\n", (rxcfg.mgc_value));
			IIO_ENSURE(cfg_ad9361_streaming_ch_mgc(ctx, &rxcfg, RX, 0) && "RX port 0 not found");
		}

		if (update_lo)
		{
			update_lo = 0;
			printf("set LO=%lld \r\n", (rxcfg.lo_hz));
			IIO_ENSURE(cfg_ad9361_streaming_ch_LO(ctx, &rxcfg, RX, 0) && "RX port 0 not found");
		}

	}
}

struct command
{
	unsigned char cmd;
	unsigned int param;
}__attribute__((packed));

static void *command_worker(void *arg)
{
	int left, received = 0;
	fd_set readfds;
	struct command cmd =
	{ 0, 0 };
	struct timeval tv =
	{ 1, 0 };
	int r = 0;

	uint32_t tmp;
	//struct stream_cfg rxcfg;
	//rxcfg.rfport = "A_BALANCED";
	//rxcfg.bw_hz = MHZ(2);   // 2 MHz rf bandwidth

	while (1)
	{
		left = sizeof(cmd);
		while (left > 0)
		{
			FD_ZERO(&readfds);
			FD_SET(s, &readfds);
			tv.tv_sec = 1;
			tv.tv_usec = 0;
			r = select(s + 1, &readfds, NULL, NULL, &tv);
			if (r)
			{
				received = recv(s, (char*) &cmd + (sizeof(cmd) - left), left, 0);
				left -= received;
				//printf("comm recv %d byte\n",received);
			}

			if (received == SOCKET_ERROR || do_exit)
			{
				printf("comm recv bye\n");
				sighandler(0);
				pthread_exit(0);
				return;
				//pthread_exit(NULL);
			}
		}

		//printf("comm recv \n");

		switch (cmd.cmd)
		{
		case 0x01:
			rxcfg.lo_hz = (long long) ntohl(cmd.param);
			if (rxcfg.lo_hz < 80000000LL)
			{
				rxcfg.lo_hz = 80000000LL;
			}
//			rxcfg.fs_hz = fs;   // 2.5 MS/s rx sample rate
//			rxcfg.lo_hz = freq; // 2.5 GHz rf frequency
//			rxcfg.rfport = "A_BALANCED"; // port A (select for rf freq.)
			//IIO_ENSURE(cfg_ad9361_streaming_ch(ctx, &rxcfg, RX, 0) && "RX port 0 not found");

			//printf("set freq %d\n", ntohl(cmd.param));
			update_lo = 1;

			//rtlsdr_set_center_freq(dev, ntohl(cmd.param));
			break;
		case 0x02:
			rxcfg.fs_hz = (long long) ntohl(cmd.param);
			update_cmd = 1;
			//IIO_ENSURE(cfg_ad9361_streaming_ch(ctx, &rxcfg, RX, 0) && "RX port 0 not found");
			printf("set sample rate %d\n", ntohl(cmd.param));
			//rtlsdr_set_sample_rate(dev, ntohl(cmd.param));
			break;
		case 0x03:
			tmp = ntohl(cmd.param);
			if (tmp == 0)
			{
				rxcfg.gian_control_mode = "fast_attack"; //manual
			}
			else
			{
				rxcfg.gian_control_mode = "manual"; //manual
			}
			printf("set gain mode %d %s\n", tmp, rxcfg.gian_control_mode);
			update_cmd = 1;

			//rtlsdr_set_tuner_gain_mode(dev, ntohl(cmd.param));
			break;
		case 0x04:
			printf("set gain %d\n", ntohl(cmd.param));
			//rtlsdr_set_tuner_gain(dev, ntohl(cmd.param));
			break;
		case 0x05:
			printf("set freq correction %d\n", ntohl(cmd.param));
			//rtlsdr_set_freq_correction(dev, ntohl(cmd.param));
			break;
		case 0x06:
			tmp = ntohl(cmd.param);
			printf("set if stage %d gain %d\n", tmp >> 16, (short) (tmp & 0xffff));
			//rtlsdr_set_tuner_if_gain(dev, tmp >> 16, (short) (tmp & 0xffff));
			break;
		case 0x07:
			printf("set test mode %d\n", ntohl(cmd.param));
			//rtlsdr_set_testmode(dev, ntohl(cmd.param));
			break;
		case 0x08:
			printf("set agc mode %d\n", ntohl(cmd.param));
			//rtlsdr_set_agc_mode(dev, ntohl(cmd.param));
			break;
		case 0x09:
			printf("set direct sampling %d\n", ntohl(cmd.param));
			//rtlsdr_set_direct_sampling(dev, ntohl(cmd.param));
			break;
		case 0x0a:
			printf("set offset tuning %d\n", ntohl(cmd.param));
			//rtlsdr_set_offset_tuning(dev, ntohl(cmd.param));
			break;
		case 0x0b:
			printf("set rtl xtal %d\n", ntohl(cmd.param));
			//rtlsdr_set_xtal_freq(dev, ntohl(cmd.param), 0);
			break;
		case 0x0c:
			printf("set tuner xtal %d\n", ntohl(cmd.param));
			//rtlsdr_set_xtal_freq(dev, 0, ntohl(cmd.param));
			break;
		case 0x0d:
			tmp = ntohl(cmd.param);
			//printf("set tuner gain by index %d\n", tmp);
			rxcfg.mgc_value = tmp;
			update_mgc = 1;
			break;
		case 0x0e:
			printf("set bias tee %d\n", ntohl(cmd.param));
			//rtlsdr_set_bias_tee(dev, (int) ntohl(cmd.param));
			break;
		default:
			break;
		}
		cmd.cmd = 0xff;
	}
}
//--nohup ./adXXx &
int main(int argc, char **argv)
{
	int r, opt, i;
	char *addr = "192.168.2.1";
	char *port = "1234";

	struct sockaddr_in server, client;

	uint32_t frequency = 100000000, samp_rate = 2048000;
	struct sockaddr_storage local, remote;
	struct addrinfo *ai;
	struct addrinfo *aiHead;
	struct addrinfo hints;
	char hostinfo[NI_MAXHOST];
	char portinfo[NI_MAXSERV];
	char remhostinfo[NI_MAXHOST];
	char remportinfo[NI_MAXSERV];
	int aiErr;
	uint32_t buf_num = 0;
	int dev_index = 0;
	int dev_given = 0;
	int gain = 0;
	int ppm_error = 0;
	struct llist *curelem, *prev;
	pthread_attr_t attr;
	void *status;
	struct timeval tv =
	{ 1, 0 };
	struct linger ling =
	{ 1, 0 };
	SOCKET listensocket = 0;
	socklen_t rlen;
	fd_set readfds;
	u_long blockmode = 1;
	//dongle_info_t dongle_info;
	struct sigaction sigact, sigign;
	dongle_info_t dongle_info;
	dongle_info.tuner_type = 4;
	dongle_info.tuner_gain_count = 70;
	sprintf(dongle_info.magic,"AD9361_SDR");

	//----------------------- sdr ---

	// RX and TX sample counters
	size_t nrx = 0;
	size_t ntx = 0;

	// Stream configurations
	//struct stream_cfg rxcfg;
	struct stream_cfg txcfg;

	pthread_mutex_init(&exit_cond_lock, NULL);
	pthread_mutex_init(&ll_mutex, NULL);
	pthread_mutex_init(&exit_cond_lock, NULL);
	pthread_cond_init(&cond, NULL);
	pthread_cond_init(&exit_cond, NULL);

	//----------NET  ---------------
	//Create socket
	listensocket = socket(AF_INET, SOCK_STREAM, 0);
	if (listensocket == -1)
	{
		printf("Could not create socket");
	}
	puts("Socket created");

	//Prepare the sockaddr_in structure
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = INADDR_ANY;
	server.sin_port = htons(8002);

	setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *) &r, sizeof(int));
	setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *) &ling, sizeof(ling));

	//Bind
	if (bind(listensocket, (struct sockaddr *) &server, sizeof(server)) < 0)
	{
//print the error message
		perror("bind failed. Error");
		return 1;
	}
	puts("bind done");

	//Listen
	//listen(listensocket, 1);

	r = fcntl(listensocket, F_GETFL, 0);
	r = fcntl(listensocket, F_SETFL, r | O_NONBLOCK);

	//---------------------------
	rxcfg.bw_hz = MHZ(20);   // 2 MHz rf bandwidth
	rxcfg.fs_hz = MHZ(2.4);   // 2.5 MS/s rx sample rate
	rxcfg.lo_hz = MHZ(91.4); // 2.5 GHz rf frequency
	rxcfg.rfport = "A_BALANCED"; // port A (select for rf freq.)
	rxcfg.gian_control_mode = "manual"; //manual
	rxcfg.mgc_value = 0;

	// TX stream config
	txcfg.bw_hz = MHZ(20.0); // 1.5 MHz rf bandwidth
	txcfg.fs_hz = MHZ(2.4);   // 2.5 MS/s tx sample rate
	txcfg.lo_hz = MHZ(100.5);  // 2.5 GHz rf frequency
	txcfg.rfport = "A"; // port A (select for rf freq.)

	printf("* Acquiring IIO context\n");
	if (argc == 1)
	{
		IIO_ENSURE((ctx = iio_create_default_context()) && "No context");
	}
	else if (argc == 2)
	{
		//IIO_ENSURE((ctx = iio_create_context_from_uri(argv[1])) && "No context");
		IIO_ENSURE((ctx = iio_create_context_from_uri("ip:127.0.0.1")) && "No context");
	}
	IIO_ENSURE(iio_context_get_devices_count(ctx) > 0 && "No devices");

	printf("* Acquiring AD9361 streaming devices\n");
	//IIO_ENSURE(get_ad9361_stream_dev(ctx, TX, &tx) && "No tx dev found");
	IIO_ENSURE(get_ad9361_stream_dev(ctx, RX, &rx) && "No rx dev found");

	printf("* Configuring AD9361 for streaming\n");
	IIO_ENSURE(cfg_ad9361_streaming_ch(ctx, &rxcfg, RX, 0) && "RX port 0 not found");
	//IIO_ENSURE(cfg_ad9361_streaming_ch(ctx, &txcfg, TX, 0) && "TX port 0 not found");

	printf("* Initializing AD9361 IIO streaming channels\n");
	IIO_ENSURE(get_ad9361_stream_ch(ctx, RX, rx, 0, &rx0_i) && "RX chan i not found");
	IIO_ENSURE(get_ad9361_stream_ch(ctx, RX, rx, 1, &rx0_q) && "RX chan q not found");
	//IIO_ENSURE(get_ad9361_stream_ch(ctx, TX, tx, 0, &tx0_i) && "TX chan i not found");
	//IIO_ENSURE(get_ad9361_stream_ch(ctx, TX, tx, 1, &tx0_q) && "TX chan q not found");

	printf("* Enabling IIO streaming channels\n");
	iio_channel_enable(rx0_i);
	iio_channel_enable(rx0_q);
	//iio_channel_enable(tx0_i);
	//iio_channel_enable(tx0_q);

	printf("* Creating non-cyclic IIO buffers with 1 MiS\n");
	rxbuf = iio_device_create_buffer(rx, 1024 * 1024, false);
	if (!rxbuf)
	{
		perror("Could not create RX buffer");
		shutdown1();
	}
	printf("app while..........\r\n");

	///----------------

	while (1)
	{
		out:

		printf("listening...\n");
		printf("IQ Data Server Start .\n");
		listen(listensocket, 1);
		do_exit = 0;

		while (1)
		{
			FD_ZERO(&readfds);
			FD_SET(listensocket, &readfds);
			tv.tv_sec = 1;
			tv.tv_usec = 0;
			r = select(listensocket + 1, &readfds, NULL, NULL, &tv);
			if (do_exit)
			{
				goto out;
			}
			else if (r)
			{
				rlen = sizeof(remote);
				s = accept(listensocket, (struct sockaddr *) &remote, &rlen);
				break;
			}
		}

		setsockopt(s, SOL_SOCKET, SO_LINGER, (char *) &ling, sizeof(ling));

		getnameinfo((struct sockaddr *) &remote, rlen, remhostinfo, NI_MAXHOST, remportinfo, NI_MAXSERV, NI_NUMERICSERV);
		printf("client accepted! %s %s\n", remhostinfo, remportinfo);

		r = send(s, (const char *) &dongle_info, sizeof(dongle_info), 0);
		if (sizeof(dongle_info) != r)
			printf("failed to send dongle information\n");

		printf("start task .........\n");
		pthread_attr_init(&attr);
		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
		r = pthread_create(&tcp_worker_thread, &attr, tcp_worker, NULL);
		r = pthread_create(&command_thread, &attr, command_worker, NULL);
		pthread_attr_destroy(&attr);

	}

	closesocket(listensocket);
	closesocket(s);
	printf("bye!!!!!!!!!!!!\n");
}

